<?php
/**
 * En:icTmp
 * Zh:基于SpeedPHP的临时文件生成器以及垃圾收集器类
 * 
 * En:icTmp provide functions
 * Base on SpeedPHP, use Extension method which means its much easier and more convenient.
 * Default tmp directory is:/tmp/icTmp/ (You can fix it)
 * Tmp files will save to the directory, and you can define an expire.
 * The file which is expired will be deleted by Gabbage Collecter.
 * Tmp files name will be kept secret if you need.
 * Gabbage Collecter will run, and depends on the rate you defined.
 * 
 * Zh:icTmp提供以下功能
 * 基于SpeedPHP并集成在SpeedPHP内，使用扩展的方式使用，简单快捷，并统一将文件保存在/tmp/icTmp/下，此目录可更改。
 * 将临时文件保存在指于目录下，并可指定文件有效时间。
 * 超出指定有效时间的文件，将被垃圾收集器清除。
 * 临时文件文件名可选择是否md5加密处理，以防止非法访问。
 * 垃圾收集器将在指定概率下运行，此概率可以更改。
 * 
 * @author	Pony
 * @version	2011-02-18 
 * 
 */

class icTmp{
	/**
	 * Z:icTmp 设置参数
	 * E:icTmp configs
	 * @var array
	 */
	private $params = array(
			'ICTMP_DIR' => './tmp/icTmp/',		//Z:保存临时文件的文件夹 E:The directory that saves tmpfiles
			'DEFAULT_EXPIRE' => 3600,					//Z:临时文件有效期，单位，秒 E:The expire, second.
			'GC_RUN_RATE' => 10							//Z:垃圾收集器运行概率，0-100，数值越高，运行概率越大 E:Gabbage Collecter run-rate, 0-100, the larger number, the higher rate.
	);
	
	/**
	 * 基于SpeedPHP的临时文件生成器以及垃圾收集器类
	 * ,每次执行构造函数时，该类都会计算一次概率，以便启动垃圾收集器，请选择合适你的概率
	 */
	public function __construct(){
		if($this->params['GC_RUN_RATE'] >= mt_rand(1, 100)){
			$this->deleteExpired();
		}
	}
	
	/**
	 * 克隆指定路径文件到临时文件夹
	 * 并可指定临时文件过期时间
	 * @param string $origin 原始文件路径
	 * @param int $expire 过期时间
	 * @param string $newname 指定的新文件名
	 * @param bool $secret 临时文件名是否加密，默认为假值，不加密
	 * @return string/bool 成功克隆则返回临时文件绝对路径，失败则返回假值
	 */
	public function cloneToTmp($origin,$expire,$newname = NULL,$secret = FALSE){
		if(!is_file($origin))return FALSE;
		if(empty($newname)){
			$newname = $secret ? md5(basename($origin)) : basename($origin);
		}
		if($this -> defineExpire($newname, $expire)){
			if(copy($origin, $this->params['ICTMP_DIR'].$newname)){
				return $this->params['ICTMP_DIR'].$newname;
			}
		}
		return FALSE;
	}
	
	/**
	 * 写入指定内容到指定临时文件
	 * 并可指定临时文件过期时间
	 * @param string $filename 指定的临时文件
	 * @param string $context 内容
	 * @param int $expire 过期时间
	 * @param string/bool $secret 临时文件名是否加密，默认为假值，不加密
	 * @return string/bool 成功写入则返回临时文件绝对路径，失败则返回假值
	 */
	public function writeToTmp($filename,$context,$expire,$secret = FALSE){
		if($secret){$filename = md5($filename);}
		if(file_put_contents($this->params['ICTMP_DIR'].$filename, $context)){
			if($this->defineExpire($filename,$expire))return $this->params['ICTMP_DIR'].$filename;
		}
		return FALSE;
	}
	
	/**
	 * 定义指定文件的过期时间
	 * @param string $filename 指定文件的文件名
	 * @param int $expire 过期时间
	 * @return bool 成功设置则返回真值，否则假值
	 */
	public function defineExpire($filename,$expire = NULL){
		if($expire == $this->params['DEFAULT_EXPIRE'] || empty($expire))return TRUE;
		$expire_time = time()+$expire;
		return file_put_contents($this->params['ICTMP_DIR'].'expire/'.$filename, $expire_time);
	}
	
	/**
	 * 垃圾收集器
	 */
	public function deleteExpired(){
		/**
		 * 删除已定义过期时间的文件
		 * 扫描expire下所有的文件，并读取它们的内容（即过期时间），若表明已过期，则删除icTmp下对应的文件及自身
		 * @var array $defines 记录所有已定义的文件，以便在下一规则执行时进行跳过操作
		 */
		$expiredir = new DirectoryIterator($this->params['ICTMP_DIR'].'expire');
		$defines = array();
		foreach($expiredir as $fileinfo){
	    	if (!$fileinfo->isDot()){
	    		$filename = $fileinfo -> getFilename();
	    		$expiretime = file_get_contents($this->params['ICTMP_DIR'].'expire/'.$filename);
	    		if($expiretime < time()){
	    			@unlink($this->params['ICTMP_DIR'].$filename);
	    			@unlink($this->params['ICTMP_DIR'].$filename);
	    		}
	    		else{
	    			$defines[$filename] = TRUE;
	    		}
	    	}
		}
		
		/**
		 * 删除未定义的过期文件
		 * 扫描icTmp下所有的未定义过期时间文件，若文件在默认过期时间内没有变动，则删除
		 */
		
		$dir = new DirectoryIterator($this->params['ICTMP_DIR']);
		foreach ($dir as $fileinfo){
			if(!$fileinfo->isDot() && $defines[$fileinfo-> getFilename()] != TRUE ){
				$ctime = $fileinfo -> getCTime();
				if((time() - $ctime) > $this->params['DEFAULT_EXPIRE']){
					@unlink($this->params['ICTMP_DIR'].$fileinfo -> getFilename());
				}
			}
		}
	}
}